and GDB is attached.
It may be necessary for gdb and the console to share a serial port.
This patch utilises the GDB protocol to encode console output.
Based on a patch from Tony Breeds <tony@bakeyournoodle.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
gdb_send_packet(ctx);
}
+static void
+gdbstub_attach(struct gdb_context *ctx)
+{
+ static void gdbstub_console_puts(const char *str);
+ if ( ctx->currently_attached )
+ return;
+ ctx->currently_attached = 1;
+ ctx->console_steal_id = console_steal(ctx->serhnd, gdbstub_console_puts);
+}
+
+static void
+gdbstub_detach(struct gdb_context *ctx)
+{
+ if ( !ctx->currently_attached )
+ return;
+ ctx->currently_attached = 0;
+ console_giveback(ctx->console_steal_id);
+}
+
/* command dispatcher */
static int
process_command(struct cpu_user_regs *regs, struct gdb_context *ctx)
gdb_arch_read_reg(addr, regs, ctx);
break;
case 'D':
- ctx->currently_attached = 0;
+ gdbstub_detach(ctx);
gdb_send_reply("OK", ctx);
/* fall through */
case 'k':
ctx->in_buf[1] )
addr = str2ulong(&ctx->in_buf[1], sizeof(unsigned long));
if ( ctx->in_buf[0] != 'D' )
- ctx->currently_attached = 1;
+ gdbstub_attach(ctx);
resume = 1;
gdb_arch_resume(regs, addr, type, ctx);
break;
static struct gdb_context
__gdb_ctx = {
- .serhnd = -1,
- .currently_attached = 0,
- .running = ATOMIC_INIT(1),
- .connected = 0,
- .signum = 1,
- .in_bytes = 0,
- .out_offset = 0,
- .out_csum = 0,
+ .serhnd = -1,
+ .running = ATOMIC_INIT(1),
+ .signum = 1
};
static struct gdb_context *gdb_ctx = &__gdb_ctx;
+static void
+gdbstub_console_puts(const char *str)
+{
+ const char *p;
+
+ gdb_start_packet(gdb_ctx);
+ gdb_write_to_packet_char('O', gdb_ctx);
+
+ for ( p = str; *p != '\0'; p++ )
+ {
+ gdb_write_to_packet_char(hex2char((*p>>4) & 0x0f), gdb_ctx );
+ gdb_write_to_packet_char(hex2char((*p) & 0x0f), gdb_ctx );
+ }
+
+ gdb_send_packet(gdb_ctx);
+}
+
/* trap handler: main entry point */
int
__trap_to_gdb(struct cpu_user_regs *regs, unsigned long cookie)
gdb_arch_enter(regs);
gdb_ctx->signum = gdb_arch_signal_num(regs, cookie);
+
/* If gdb is already attached, tell it we've stopped again. */
if ( gdb_ctx->currently_attached )
{
static char serial_rx_ring[SERIAL_RX_SIZE];
static unsigned int serial_rx_cons, serial_rx_prod;
+static void (*serial_steal_fn)(const char *);
+
+int console_steal(int handle, void (*fn)(const char *))
+{
+ if ( (handle == -1) || (handle != sercon_handle) )
+ return 0;
+
+ if ( serial_steal_fn == NULL )
+ return -EBUSY;
+
+ serial_steal_fn = fn;
+ return 1;
+}
+
+void console_giveback(int id)
+{
+ if ( id == 1 )
+ serial_steal_fn = NULL;
+}
+
+static void sercon_puts(const char *s)
+{
+ if ( serial_steal_fn != NULL )
+ (*serial_steal_fn)(s);
+ else
+ serial_puts(sercon_handle, s);
+}
+
/* CTRL-<switch_char> switches input direction between Xen and DOM0. */
#define SWITCH_CODE (opt_conswitch[0]-'a'+1)
static int xen_rx = 1; /* FALSE => serial input passed to domain 0. */
return -EFAULT;
kbuf[kcount] = '\0';
- serial_puts(sercon_handle, kbuf);
+ sercon_puts(kbuf);
for ( kptr = kbuf; *kptr != '\0'; kptr++ )
vga_putchar(*kptr);
{
int c;
- serial_puts(sercon_handle, str);
+ sercon_puts(str);
while ( (c = *str++) != '\0' )
{
/* Print oldest portion of the ring. */
ASSERT(debugtrace_buf[debugtrace_bytes - 1] == 0);
- serial_puts(sercon_handle, &debugtrace_buf[debugtrace_prd]);
+ sercon_puts(&debugtrace_buf[debugtrace_prd]);
/* Print youngest portion of the ring. */
debugtrace_buf[debugtrace_prd] = '\0';
- serial_puts(sercon_handle, &debugtrace_buf[0]);
+ sercon_puts(&debugtrace_buf[0]);
memset(debugtrace_buf, '\0', debugtrace_bytes);
void console_start_sync(void);
void console_end_sync(void);
+/*
+ * Steal output from the console. Returns +ve identifier, else -ve error.
+ * Takes the handle of the serial line to steal, and steal callback function.
+ */
+int console_steal(int handle, void (*fn)(const char *));
+
+/* Give back stolen console. Takes the identifier returned by console_steal. */
+void console_giveback(int id);
+
#endif /* __CONSOLE_H__ */
unsigned long str2ulong(const char *str, unsigned long bytes);
struct gdb_context {
- int serhnd;
+ int serhnd; /* handle on our serial line */
+ int console_steal_id; /* handle on stolen console */
int currently_attached:1;
atomic_t running;
unsigned long connected;